AudioClipA single decoded audio clip that can send its signal to a Channel or a Master, be played, looped, analyzed, and controlled over time.
import { AudioClip } from "@fluex/fluexgl-dsp";
const clip = new AudioClip(data);
clip.send(myChannel);
// Basic settings
clip.setVolume(0.8);
clip.setPanLevel(-0.2);
clip.setLoop(true);
// Start playback
clip.play();
// Manually seek to 30 seconds
clip.seek(30);
Constructs a new AudioClip from pre-decoded source data.
new AudioClip(data: AudioSourceData): AudioClip;
data: AudioSourceData - A typed object created when calling loadAudioSource() or loadAudioSourceFromBlob().id: stringA unique id, automatically generated when constructing a new audio clip. Should NOT be changed.
label: string | nullA custom label. Can be changed.
loop: booleanWhether the clip is set to loop when played.
isPlaying: booleanIndicates whether this clip is currently playing.
startTime: numberThe AudioContext.currentTime at which the current playback started.
offsetAtStart: numberThe offset (in seconds) inside the buffer from which playback started.
playbackRate: numberThe current playback rate applied to buffer sources. Defaults to 1. Updated automatically by setPitch().
pitch: numberThe current pitch offset in semitones. Defaults to 0. Updated by setPitch()/resetPitch().
minPitchSemitones: numberThe minimum allowed pitch, in semitones, accepted by setPitch(). Defaults to -24.
maxPitchSemitones: numberThe maximum allowed pitch, in semitones, accepted by setPitch(). Defaults to 24.
progressUpdateSpeed: numberThe interval in milliseconds used to track the audio clip's time progress. Default value is 20. The progress timer only runs while the clip is playing and at least one "progress" listener is registered, and stops when the last playback has ended.
gainNode: GainNode | nullPer-clip gain node used to control volume.
stereoPannerNode: StereoPannerNode | nullPer-clip stereo panner node used to control pan level.
context: AudioContext | nullAudio context, usually inherited from the DSP's pipeline context.
audioClipPlayer: AudioClipPlayer | nullAudioClipPlayer where this audio clip is attached to.
initialize(audioClipPlayer: AudioClipPlayer): voidInitializes the audio clip using the AudioClipPlayer's audio context. Usually not needed because send(channel: Channel | Master) initializes it automatically.
audioClipPlayer: AudioClipPlayer AudioClipPlayer, which is usually automatically generated when creating a new Channel or a new Master;voidplay(timestamp?: number, offset?: number): AudioClip | nullStarts playback of the clip. The audio clip starts from the beginning if no arguments are provided.
timestamp?: number - Absolute AudioContext.currentTime at which to start. If omitted, playback starts immediately. This argument is optional.offset?: number - Offset in seconds inside the buffer to start from.
If omitted, uses the current offsetAtStart.AudioClip - The same AudioClip. Can be used to stack methods.null - Returns null if this method failed, or if the maximum number of concurrent buffer source nodes (maxAudioBufferSourceNodes) has already been reached.seek(seconds: number): AudioClip | voidSeeks to a given position (in seconds) inside the clip, clamped between 0 and duration. If the clip is currently playing, playback is stopped and restarted from the new position; otherwise offsetAtStart is updated for the next play() call.
seconds: number - The position, in seconds, to seek to.AudioClip - The same AudioClip. Can be used to stack methods.stop(): AudioClip | nullStops playback of this clip and disconnects all active buffer sources.
No arguments
AudioClip - The same AudioClip. Can be used to stack methods.null - Returns null if this method failed.setVolume(volume: number): AudioClipSets the clip volume using its GainNode.
volume: number - The desired gain value (linear)AudioClip - The same AudioClip. Can be used to stack methods.setPanLevel(panLevel: number): AudioClipSets the stereo pan level of the clip. Must be between -1 and 1.
panLevel: number - Pan value between -1 (full left) and 1 (full right).AudioClip - The same AudioClip. Can be used to stack methods.setLoop(loop?: boolean): AudioClipEnables or disables looping of this clip.
loop?: boolean - When omitted, defaults to true.AudioClip - The same AudioClip. Can be used to stack methods.setMaxAudioBufferSourceNodes(value: number): AudioClipSets the maximum number of buffer source nodes (default 1). This can only be changed if the overrideMaxAudioBufferNodes property on DSP is set to true; otherwise a warning is logged and the value is left unchanged.
value: number - The desired maximum amount of buffer source nodes.AudioClip - The same AudioClip. Can be used to stack methods.disconnectAllAudioBufferSourceNodes(): booleanStops and disconnects every currently active buffer source node for this clip.
No arguments
boolean - true if the operation ran, false if this clip has no context.setPitch(semitones: number): AudioClipSets the pitch of the clip in semitones, recalculating and applying the equivalent playbackRate (2 ^ (semitones / 12)) to all active buffer sources.
semitones: number - The desired pitch offset in semitones. Must be between minPitchSemitones and maxPitchSemitones.AudioClip - The same AudioClip. Can be used to stack methods.resetPitch(): AudioClipResets the pitch back to 0 semitones. Shorthand for setPitch(0).
No arguments
AudioClip - The same AudioClip. Can be used to stack methods.setPlaybackRateInSemitones(semitones: number): AudioClipDeprecated. Use
setPitch()instead.
semitones: number - The desired pitch offset in semitones.AudioClip - The same AudioClip. Can be used to stack methods.getChannelData(channel?: number): Float32ArrayReturns the raw PCM sample data for a single channel of the underlying AudioBuffer.
channel?: number - Zero-based channel index. Defaults to 0.Float32ArrayaddEventListener<K extends keyof AudioClipEventMap>(event: K, cb: AudioClipEventMap[K]): () => voidRegisters a listener for clip events.
event: K (keyof AudioClipEventMap) - Event name (e.g. "progress").cb: (event: (event from keyof AudioClipEventMap)) => void - Callback function.() => void - Unsubscribe function to remove the listener.once<K extends keyof AudioClipEventMap>(event: K, cb: AudioClipEventMap[K]): () => voidRegisters a one-time event listener that automatically removes itself after the first call.
event: K (keyof AudioClipEventMap) - Event name (e.g. "progress").cb: (event: (event from keyof AudioClipEventMap)) => void - Callback function.() => void - Unsubscribe function to remove the listener.removeEventListener<K extends keyof AudioClipEventMap>(event: K, cb: AudioClipEventMap[K]): AudioClipRemoves a specific listener from an event.
event: K (keyof AudioClipEventMap) - Event name (e.g. "progress").cb: (event: (event from keyof AudioClipEventMap)) => void - Callback function.AudioClip - The same instance, for chaining.clearEventListeners(event?: keyof AudioClipEventMap): AudioClipClears event listeners.
event?: keyof AudioClipEventMap - If provided, clears listeners only for that event.AudioClip - The same instance, for chainingsend(channel: Channel | Master): voidAttaches this audio clip to a Channel or a Master and sends its signal to the channel.
voidunsend(channel: Channel | Master): voidDetaches this audio clip from a Channel or a Master and stops sending this clip's signal to the channel.
voiddetachFromAudioClipPlayer(audioClipPlayer: AudioClipPlayer): voidDetaches this clip from a specific AudioClipPlayer. If that player was the clip's active player, the next remaining player (if any) becomes active. If no players remain, the clip is stopped.
audioClipPlayer: AudioClipPlayer - The player to detach from.void"progress"Emitted periodically while the clip is playing, on an interval controlled by progressUpdateSpeed.
Payload type (AudioClipOnProgressEvent):
type ProgressPayload = {
current: number; // Current playback position in seconds
startTime: number; // AudioContext timestamp when playback started
offset: number; // Offset in seconds at which playback started
contextTimestamp: number; // Current AudioContext.currentTime
formatted: string; // Human readable time, e.g. "01:23"
};
Registered via
clip.addEventListener("progress", (event) => {
console.log(event.current, event.formatted);
});
"initialize"Emitted once, right after initialize() finishes wiring up this clip's audio nodes.
Payload (simplified):
type InitializePayload = {
durationOfInitialization: number; // Time in ms the initialization took
context: AudioContext | null;
};
"play"Emitted every time play() successfully starts a new buffer source.
Payload (simplified):
type PlayPayload = {
timestamp: number; // Date.now() at play time
audioBufferSourceNodes: AudioBufferSourceNode[]; // All currently active buffer sources
context: AudioContext;
};
get currentPlaybackTime(): numberReturns the current playback time in seconds relative to the start of the buffer. Returns 0 when the clip is not playing or no audio context is available. Otherwise: offsetAtStart + (audioContext.currentTime - startTime).
get duration(): numberTotal duration of the underlying audio buffer in seconds.
get volume(): numberCurrent gain value read from gainNode. Returns 0 when no gain node is available.
get stereoPanning(): numberCurrent pan value read from stereoPannerNode. Returns 1 when no stereo panner node is available.
get formattedDuration(): stringDuration formatted as "mm:ss".
get sampleRate(): numberSample rate of the underlying AudioBuffer.
get numberOfChannels(): numberNumber of channels in the underlying AudioBuffer.
get byteLength(): numberByte length of the original ArrayBuffer used to construct this clip.
import { DspPipeline, loadAudioSource, AudioClip } from "@fluex/fluexgl-dsp";
(async function() {
const pipeline = new DspPipeline({
pathToWasm: "/data/fluexgl-dsp-wasm_bg.wasm",
pathToWorklet: "/data/fluexgl-dsp-processor.worklet"
});
await pipeline.initializeDpsPipeline();
const audioDevice = await pipeline.resolveDefaultAudioOutputDevice();
if(!audioDevice) return;
const audioSource = await loadAudioSource("/music.mp3");
if(!audioSource) return;
const audioClip = new AudioClip(audioSource);
const myChannel = audioDevice.createChannel();
audioClip.send(myChannel);
myChannel.send(audioDevice.getMasterChannel());
window.addEventListener("mousedown", function() {
audioClip.play();
});
})();
import { DspPipeline, loadAudioSource, AudioClip } from "@fluex/fluexgl-dsp";
(async function() {
const pipeline = new DspPipeline({
pathToWasm: "/data/fluexgl-dsp-wasm_bg.wasm",
pathToWorklet: "/data/fluexgl-dsp-processor.worklet",
options: {
overrideMaxAudioBufferNodes: true
}
});
await pipeline.initializeDpsPipeline();
const audioDevice = await pipeline.resolveDefaultAudioOutputDevice();
if(!audioDevice) return;
const audioSource = await loadAudioSource("/single-gun-shot.mp3");
if(!audioSource) return;
const audioClip = new AudioClip(audioSource);
const myChannel = audioDevice.createChannel();
audioClip.setMaxAudioBufferSourceNodes(200);
audioClip.send(myChannel);
myChannel.send(audioDevice.getMasterChannel());
let lastTimestamp = Date.now();
let isShooting = false;
let shootDelayInMs = 100;
function loop() {
const now = Date.now();
if((now - lastTimestamp >= shootDelayInMs) && isShooting) {
audioClip.play();
lastTimestamp = now;
}
return window.requestAnimationFrame(loop);
}
window.addEventListener("mousedown", function() { isShooting = true; });
window.addEventListener("mouseup", function() { isShooting = false; });
loop();
})();